package cn.sumpu.shared.maven.autoconf;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

/**
 * 
 * @goal conf
 */
public class AutoConfMojo extends AbstractMojo {
	/**
	 * 
	 * @parameter expression="${conf.file}" default-value=""
	 */
	private String confFile;

	/**
	 * 
	 * @parameter expression="${auto.conf.path}" default-value=""
	 */
	private String autoConfPath;

	/**
	 * 
	 * @parameter expression="${dest.path}" default-value=""
	 */
	private String destPath;

	private VelocityEngine velocityEngine = new VelocityEngine();

	private final String fileSep = System.getProperty("file.separator");

	public void execute() throws MojoExecutionException {
		Properties props = loadProperties();
		autoConf(props);
	}

	@SuppressWarnings("unchecked")
	private void autoConf(Properties props) {
		SAXBuilder builder = new SAXBuilder();
		Document doc = null;
		try {
			StringBuilder sb = new StringBuilder(autoConfPath);
			sb.append(fileSep).append("META-INF").append(fileSep)
					.append("autoconf").append(fileSep).append("auto-conf.xml");
			Reader in = new FileReader(sb.toString());
			doc = builder.build(in);
			Element root = doc.getRootElement();

			Map<String, String> templateParams = new HashMap<String, String>();
			List<Element> groupList = root.getChildren("group");
			for (Element group : groupList) {
				List<Element> propertyList = group.getChildren();
				for (Element property : propertyList) {
					String name = property.getAttributeValue("name");
					if (null == name || name.length() <= 0) {
						getLog().error("property's name must have value!");
					}
					String value = props.getProperty(name);
					if (null == value || value.length() <= 0) {
						value = property.getAttributeValue("defaultValue");
						if (null == value || value.length() <= 0) {
							String msg = "'" + name + "' must have a value!";
							getLog().error(msg);
							throw new Exception(msg);
						}
					}
					String key = name.replace(".", "_");
					templateParams.put(key, value);
				}
			}

			List<Element> scriptList = root.getChildren("script");
			for (Element script : scriptList) {
				List<Element> generateList = script.getChildren();
				for (Element generate : generateList) {
					String template = generate.getAttributeValue("template");
					String destfile = generate.getAttributeValue("destfile");
					String charset = generate.getAttributeValue("charset");
					generate(template, templateParams, destPath + fileSep
							+ destfile, charset);
					getLog().info(
							template + " ===> " + destPath + fileSep + destfile);
				}
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private void generate(String template, Map<String, String> templateParams,
			String destfile, String charset) {
		BufferedWriter bw = null;
		FileOutputStream fos = null;
		try {
			Properties p = new Properties();
			p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
			p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
			p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, autoConfPath
					+ fileSep + "META-INF" + fileSep + "autoconf" + fileSep);
			velocityEngine.init(p);

			Template t = velocityEngine.getTemplate(template);
			VelocityContext context = new VelocityContext();
			Set<String> keys = templateParams.keySet();
			for (String key : keys) {
				context.put(key, templateParams.get(key));
			}
			fos = new FileOutputStream(destfile);
			bw = new BufferedWriter(new OutputStreamWriter(fos, charset));
			t.merge(context, bw);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				bw.close();
				fos.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private Properties loadProperties() {
		if (null == confFile || confFile.length() <= 0) {
			confFile = System.getProperty("user.home") + fileSep
					+ "conf.properties";
		}
		getLog().info("conf.file: " + confFile);
		Properties prop = new Properties();
		try {
			prop.load(new BufferedReader(new java.io.FileReader(confFile)));
			return prop;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	// just test
	public static void main(String[] args) {
		AutoConfMojo autoConf = new AutoConfMojo();
		Properties props = autoConf.loadProperties();
		autoConf.autoConf(props);
	}
}